<?php

namespace ORM;

use Database\Connection;

abstract class Model {
    /**
     * 数据库连接实例
     */
    protected static $connection;
    
    /**
     * 表名
     */
    protected $table;
    
    /**
     * 主键
     */
    protected $primaryKey = 'id';
    
    /**
     * 是否自动维护时间戳
     */
    protected $timestamps = true;
    
    /**
     * 创建时间字段
     */
    const CREATED_AT = 'created_at';
    
    /**
     * 更新时间字段
     */
    const UPDATED_AT = 'updated_at';
    
    /**
     * 模型属性
     */
    protected $attributes = [];
    
    /**
     * 原始属性（用于检测变更）
     */
    protected $original = [];
    
    /**
     * 已变更的属性
     */
    protected $changes = [];
    
    /**
     * 关联关系
     */
    protected $relations = [];
    
    /**
     * 可填充的属性
     */
    protected $fillable = [];
    
    /**
     * 不可填充的属性
     */
    protected $guarded = ['id'];
    
    /**
     * 隐藏的属性（不会被序列化）
     */
    protected $hidden = [];
    
    /**
     * 可见的属性（会被序列化）
     */
    protected $visible = [];
    
    /**
     * 属性类型转换
     */
    protected $casts = [];
    
    /**
     * 构造函数
     */
    public function __construct(array $attributes = []) {
        $this->fill($attributes);
    }
    
    /**
     * 设置数据库连接
     */
    public static function setConnection(Connection $connection) {
        static::$connection = $connection;
    }
    
    /**
     * 获取数据库连接
     */
    public static function getConnection() {
        if (static::$connection === null) {
            throw new \Exception("数据库连接未设置");
        }
        
        return static::$connection;
    }
    
    /**
     * 获取表名
     */
    public function getTable() {
        if ($this->table) {
            return $this->table;
        }
        
        // 从类名推断表名
        $className = get_class($this);
        $className = substr($className, strrpos($className, '\\') + 1);
        return strtolower($className) . 's';
    }
    
    /**
     * 设置表名
     */
    public function setTable($table) {
        $this->table = $table;
        return $this;
    }
    
    /**
     * 获取主键
     */
    public function getPrimaryKey() {
        return $this->primaryKey;
    }
    
    /**
     * 获取主键值
     */
    public function getKey() {
        return $this->getAttribute($this->primaryKey);
    }
    
    /**
     * 填充属性
     */
    public function fill(array $attributes) {
        foreach ($attributes as $key => $value) {
            if ($this->isFillable($key)) {
                $this->setAttribute($key, $value);
            }
        }
        
        return $this;
    }
    
    /**
     * 判断属性是否可填充
     */
    public function isFillable($key) {
        if (in_array($key, $this->guarded)) {
            return false;
        }
        
        if (in_array('*', $this->guarded)) {
            return in_array($key, $this->fillable);
        }
        
        return empty($this->fillable) || in_array($key, $this->fillable) || in_array('*', $this->fillable);
    }
    
    /**
     * 设置属性
     */
    public function setAttribute($key, $value) {
        // 检查是否有自定义的setter方法
        $setter = 'set' . ucfirst($key) . 'Attribute';
        
        if (method_exists($this, $setter)) {
            $value = $this->$setter($value);
        }
        
        // 记录原始值（如果是首次设置）
        if (!array_key_exists($key, $this->attributes)) {
            $this->original[$key] = $value;
        } elseif (!array_key_exists($key, $this->original)) {
            $this->original[$key] = $this->attributes[$key];
        }
        
        // 记录变更
        if (!array_key_exists($key, $this->original) || $this->original[$key] !== $value) {
            $this->changes[$key] = $value;
        }
        
        $this->attributes[$key] = $value;
        
        return $this;
    }
    
    /**
     * 获取属性
     */
    public function getAttribute($key) {
        if (!array_key_exists($key, $this->attributes)) {
            // 检查是否是关联关系
            if (method_exists($this, $key)) {
                return $this->getRelationValue($key);
            }
            
            return null;
        }
        
        $value = $this->attributes[$key];
        
        // 检查是否有自定义的getter方法
        $getter = 'get' . ucfirst($key) . 'Attribute';
        
        if (method_exists($this, $getter)) {
            return $this->$getter($value);
        }
        
        // 应用类型转换
        if (isset($this->casts[$key])) {
            return $this->castAttribute($key, $value);
        }
        
        return $value;
    }
    
    /**
     * 获取关联关系的值
     */
    public function getRelationValue($key) {
        // 如果关联已加载，直接返回
        if (array_key_exists($key, $this->relations)) {
            return $this->relations[$key];
        }
        
        // 否则加载关联
        if (method_exists($this, $key)) {
            $relation = $this->$key();
            
            if (isset($relation['type'])) {
                $relationManager = new RelationManager(static::getConnection());
                $method = $relation['type'];
                
                $this->relations[$key] = $relationManager->$method(
                    $this,
                    $relation['related'],
                    $relation['foreignKey'] ?? null,
                    $relation['localKey'] ?? null
                );
                
                return $this->relations[$key];
            }
        }
        
        return null;
    }
    
    /**
     * 设置关联关系
     */
    public function setRelation($relation, $value) {
        $this->relations[$relation] = $value;
        return $this;
    }
    
    /**
     * 应用类型转换
     */
    protected function castAttribute($key, $value) {
        if ($value === null) {
            return null;
        }
        
        switch ($this->casts[$key]) {
            case 'int':
            case 'integer':
                return (int) $value;
            case 'float':
            case 'double':
                return (float) $value;
            case 'string':
                return (string) $value;
            case 'bool':
            case 'boolean':
                return (bool) $value;
            case 'array':
                return json_decode($value, true);
            case 'object':
                return json_decode($value);
            case 'date':
                return date('Y-m-d', strtotime($value));
            case 'datetime':
                return date('Y-m-d H:i:s', strtotime($value));
            default:
                return $value;
        }
    }
    
    /**
     * 获取所有属性
     */
    public function getAttributes() {
        return $this->attributes;
    }
    
    /**
     * 获取已变更的属性
     */
    public function getChanges() {
        return $this->changes;
    }
    
    /**
     * 判断属性是否已变更
     */
    public function isDirty($attributes = null) {
        if ($attributes === null) {
            return !empty($this->changes);
        }
        
        $attributes = is_array($attributes) ? $attributes : func_get_args();
        
        foreach ($attributes as $attribute) {
            if (array_key_exists($attribute, $this->changes)) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 创建新的模型实例
     */
    public function newInstance($attributes = []) {
        $model = new static($attributes);
        return $model;
    }
    
    /**
     * 创建查询构建器实例
     */
    public static function query() {
        $instance = new static();
        return new QueryBuilder(static::getConnection(), $instance);
    }
    
    /**
     * 查找记录
     */
    public static function find($id) {
        return static::query()->find($id);
    }
    
    /**
     * 获取所有记录
     */
    public static function all() {
        return static::query()->get();
    }
    
    /**
     * 创建新记录
     */
    public static function create(array $attributes) {
        $model = new static($attributes);
        $model->save();
        return $model;
    }
    
    /**
     * 更新或创建记录
     */
    public static function updateOrCreate(array $attributes, array $values = []) {
        $model = static::query();
        
        foreach ($attributes as $key => $value) {
            $model->where($key, $value);
        }
        
        $instance = $model->first();
        
        if ($instance === null) {
            return static::create(array_merge($attributes, $values));
        }
        
        $instance->fill($values);
        $instance->save();
        
        return $instance;
    }
    
    /**
     * 保存模型
     */
    public function save() {
        $query = $this->newQuery();
        
        // 如果有主键值，执行更新操作
        if ($this->getKey()) {
            $saved = $this->performUpdate($query);
        } else {
            // 否则执行插入操作
            $saved = $this->performInsert($query);
        }
        
        if ($saved) {
            // 重置变更记录
            $this->changes = [];
            $this->original = $this->attributes;
        }
        
        return $saved;
    }
    
    /**
     * 执行更新操作
     */
    protected function performUpdate(QueryBuilder $query) {
        // 如果没有变更，直接返回true
        if (empty($this->changes)) {
            return true;
        }
        
        // 自动更新时间戳
        if ($this->timestamps) {
            $this->updateTimestamps();
        }
        
        // 执行更新
        return $query->where($this->primaryKey, $this->getKey())
                     ->update($this->changes);
    }
    
    /**
     * 执行插入操作
     */
    protected function performInsert(QueryBuilder $query) {
        // 自动更新时间戳
        if ($this->timestamps) {
            $this->updateTimestamps();
        }
        
        // 执行插入
        $id = $query->insert($this->attributes);
        
        // 设置主键值
        $this->setAttribute($this->primaryKey, $id);
        
        return true;
    }
    
    /**
     * 更新时间戳
     */
    protected function updateTimestamps() {
        $time = date('Y-m-d H:i:s');
        
        if (!$this->isDirty(static::UPDATED_AT)) {
            $this->setAttribute(static::UPDATED_AT, $time);
        }
        
        if (!$this->exists() && !$this->isDirty(static::CREATED_AT)) {
            $this->setAttribute(static::CREATED_AT, $time);
        }
    }
    
    /**
     * 判断模型是否已存在于数据库
     */
    public function exists() {
        return $this->getKey() !== null;
    }
    
    /**
     * 删除模型
     */
    public function delete() {
        if ($this->exists()) {
            return $this->newQuery()
                        ->where($this->primaryKey, $this->getKey())
                        ->delete();
        }
        
        return false;
    }
    
    /**
     * 创建新的查询构建器
     */
    public function newQuery() {
        return new QueryBuilder(static::getConnection(), $this);
    }
    
    /**
     * 定义一对一关系
     */
    public function hasOne($related, $foreignKey = null, $localKey = null) {
        return [
            'type' => 'hasOne',
            'related' => $related,
            'foreignKey' => $foreignKey,
            'localKey' => $localKey
        ];
    }
    
    /**
     * 定义一对多关系
     */
    public function hasMany($related, $foreignKey = null, $localKey = null) {
        return [
            'type' => 'hasMany',
            'related' => $related,
            'foreignKey' => $foreignKey,
            'localKey' => $localKey
        ];
    }
    
    /**
     * 定义多对一关系
     */
    public function belongsTo($related, $foreignKey = null, $ownerKey = null) {
        return [
            'type' => 'belongsTo',
            'related' => $related,
            'foreignKey' => $foreignKey,
            'localKey' => $ownerKey
        ];
    }
    
    /**
     * 定义多对多关系
     */
    public function belongsToMany($related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null, $parentKey = null, $relatedKey = null) {
        return [
            'type' => 'belongsToMany',
            'related' => $related,
            'table' => $table,
            'foreignPivotKey' => $foreignPivotKey,
            'relatedPivotKey' => $relatedPivotKey,
            'parentKey' => $parentKey,
            'relatedKey' => $relatedKey
        ];
    }
    
    /**
     * 动态获取属性
     */
    public function __get($key) {
        return $this->getAttribute($key);
    }
    
    /**
     * 动态设置属性
     */
    public function __set($key, $value) {
        $this->setAttribute($key, $value);
    }
    
    /**
     * 判断属性是否存在
     */
    public function __isset($key) {
        return isset($this->attributes[$key]) || 
               isset($this->relations[$key]) || 
               method_exists($this, $key);
    }
    
    /**
     * 移除属性
     */
    public function __unset($key) {
        unset($this->attributes[$key]);
        unset($this->relations[$key]);
    }
    
    /**
     * 转换为数组
     */
    public function toArray() {
        $array = [];
        
        foreach ($this->attributes as $key => $value) {
            if (in_array($key, $this->hidden)) {
                continue;
            }
            
            if (!empty($this->visible) && !in_array($key, $this->visible)) {
                continue;
            }
            
            $array[$key] = $this->getAttribute($key);
        }
        
        // 包含关联关系
        foreach ($this->relations as $key => $relation) {
            if (in_array($key, $this->hidden)) {
                continue;
            }
            
            if (!empty($this->visible) && !in_array($key, $this->visible)) {
                continue;
            }
            
            if (is_array($relation)) {
                $items = [];
                foreach ($relation as $item) {
                    if (method_exists($item, 'toArray')) {
                        $items[] = $item->toArray();
                    } else {
                        $items[] = $item;
                    }
                }
                $array[$key] = $items;
            } elseif (is_object($relation) && method_exists($relation, 'toArray')) {
                $array[$key] = $relation->toArray();
            } else {
                $array[$key] = $relation;
            }
        }
        
        return $array;
    }
    
    /**
     * 转换为JSON
     */
    public function toJson($options = 0) {
        return json_encode($this->toArray(), $options);
    }
    
    /**
     * 转换为字符串（JSON）
     */
    public function __toString() {
        return $this->toJson();
    }
    
    /**
     * 静态方法调用转发到查询构建器
     */
    public static function __callStatic($method, $parameters) {
        return static::query()->$method(...$parameters);
    }
    
    /**
     * 动态方法调用转发到查询构建器
     */
    public function __call($method, $parameters) {
        return $this->newQuery()->$method(...$parameters);
    }
}